package cn.tedu.cqhotel.service.impl;

import cn.tedu.cqhotel.ex.ServiceCode;
import cn.tedu.cqhotel.ex.ServiceException;
import cn.tedu.cqhotel.mapper.AdminMapper;
import cn.tedu.cqhotel.mapper.AdminRoleMapper;
import cn.tedu.cqhotel.mapper.RoleMapper;
import cn.tedu.cqhotel.pojo.dto.AdminAddNewDTO;
import cn.tedu.cqhotel.pojo.dto.AdminLoginInfoDTO;
import cn.tedu.cqhotel.pojo.dto.AdminUpdateInfoDTO;
import cn.tedu.cqhotel.pojo.entity.Admin;
import cn.tedu.cqhotel.pojo.entity.AdminRole;
import cn.tedu.cqhotel.pojo.vo.AdminListItemVO;
import cn.tedu.cqhotel.pojo.vo.AdminLoginInfoVO;
import cn.tedu.cqhotel.pojo.vo.AdminStandardVO;
import cn.tedu.cqhotel.security.AdminDetails;
import cn.tedu.cqhotel.service.IAdminService;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

/**
 * wangxuran
 * 管理员service实现
 */
@Slf4j
@Service
public class AdminServiceImpl implements IAdminService {

    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Value("${cqhotel.jwt.secret-key}")
    private String secretKey;
    @Value("${cqhotel.jwt.duration-in-minute}")
    private Long durationInMinute;



    /**
     * 管理员登录
     * @param adminLoginInfoDTO
     * @return
     */
    @Override
    public String login(AdminLoginInfoDTO adminLoginInfoDTO) {
        log.debug("开始处理【登录认证】的业务，参数：{}", adminLoginInfoDTO);
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                adminLoginInfoDTO.getUsername(),
                adminLoginInfoDTO.getPassword());
        Authentication authenticateResult =
                authenticationManager.authenticate(authentication);
        log.debug("Spring Security已经完成认证，且认证通过，返回的结果：{}", authenticateResult);
        log.debug("返回认证信息中的当事人（Principal）类型：{}", authenticateResult.getPrincipal().getClass().getName());
        log.debug("返回认证信息中的当事人（Principal）数据：{}", authenticateResult.getPrincipal());

        AdminDetails principal = (AdminDetails) authenticateResult.getPrincipal();
        Long id = principal.getId();
        String username = principal.getUsername();
        Collection<GrantedAuthority> authorities = principal.getAuthorities();
        String authorityListString = JSON.toJSONString(authorities);

        Map<String,Object> claims = new HashMap<>();
        claims.put("id",id);
        claims.put("username",username);
        claims.put("authorities",authorityListString);

        Date expiration = new Date(System.currentTimeMillis() + durationInMinute * 60 * 1000);

        String jwt = Jwts.builder()
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                .setClaims(claims)
                .setExpiration(expiration)
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
        log.debug("已经生成JWT数据：{}", jwt);
        return jwt;
    }

    /**
     * 新增管理员
     * @param adminAddNewDTO
     */
    @Override
    public void addNew(AdminAddNewDTO adminAddNewDTO) {
        log.debug("开始处理【添加管理员】的业务，参数：{}", adminAddNewDTO);
        String username = adminAddNewDTO.getUsername();
        int countByUsername = adminMapper.countByUsername(username);
        if (countByUsername>0){
            String message = "添加管理员失败，用户名【" + username + "】已经被占用！";
            throw new ServiceException(ServiceCode.ERR_CONFLICT,message);
        }

        String phone = adminAddNewDTO.getPhone();
        int countByPhone = adminMapper.countByPhone(phone);
        if (countByPhone>0){
            String message = "添加管理员失败，手机号码【" + phone + "】已经被占用！";
            throw new ServiceException(ServiceCode.ERR_CONFLICT,message);
        }

        String email = adminAddNewDTO.getEmail();
        int countByEmail = adminMapper.countByEmail(email);
        if (countByEmail>0){
            String message = "添加管理员失败，电子邮箱【" + email + "】已经被占用！";
            throw new ServiceException(ServiceCode.ERR_CONFLICT,message);
        }

        Admin admin = new Admin();
        BeanUtils.copyProperties(adminAddNewDTO,admin);
        admin.setLoginCount(0);
        String rawPassword = adminAddNewDTO.getPassword();
        String encodePassword = passwordEncoder.encode(rawPassword);
        admin.setPassword(encodePassword);
        int row = adminMapper.insert(admin);
        if (row!=1){
            String message = "添加管理员失败,服务器忙,请稍后再试![错误代码：1]";
            throw new ServiceException(ServiceCode.ERR_INSERT,message);
        }

        Long[] roleIds = adminAddNewDTO.getRoleIds();
        int countByIds = roleMapper.countByIds(roleIds);
        if (countByIds != roleIds.length){
            String message = "添加管理员失败，角色数据错误！";
            throw new ServiceException(ServiceCode.ERR_BAD_REQUEST,message);
        }

        Arrays.sort(roleIds);
        if (roleIds[0] == 1L){
            roleIds[0] = roleIds[roleIds.length-1];
            roleIds = Arrays.copyOf(roleIds,roleIds.length-1);
            log.debug("角色id数组中不允许包含id=1的值，处理后的结果：{}", Arrays.toString(roleIds));
        }
        if (roleIds.length == 0){
            String message = "添加管理员失败，服务器忙，请稍后再尝试！[错误代码：2]";
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }

        LocalDateTime now = LocalDateTime.now();
        List<AdminRole> adminRoleList = new ArrayList<>();
        for (Long roleId : roleIds) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleId);
            adminRole.setGmtCreate(now);
            adminRole.setGmtModified(now);
            adminRoleList.add(adminRole);
        }
        row = adminRoleMapper.insertBatch(adminRoleList);
        if (row != roleIds.length){
            String message = "添加管理员失败,服务器忙,请稍后再试![错误代码：3]";
            throw new ServiceException(ServiceCode.ERR_INSERT,message);
        }
        log.debug("添加管理员成功!");
    }

    /**
     * 根据id删除管理员
     * @param id 管理员id
     */
    @Override
    public void deleteById(Long id) {
        log.debug("开始处理【根据id删除管理员】的业务：id={}", id);
        // 不允许对id=1的管理员进行危险管理操作，返回NOT_FOUND错误，视为id=1的管理员不存在
        if (id == 1) {
            String message = "删除管理员失败！尝试访问的数据不存在！";
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if (queryResult == null) {
            String message = "删除管理员失败！尝试访问的数据不存在！";
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        int rows = adminMapper.delete(id);
        if (rows != 1) {
            String message = "删除管理员失败！服务器忙，请稍后再次尝试！[错误代码：1]";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }

        rows = adminRoleMapper.deleteByAdmin(id);
        if (rows < 1) {
            String message = "删除管理员失败！服务器忙，请稍后再次尝试！[错误代码：2]";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
    }

    /**
     * 修改管理员密码
     * @param id       管理员id
     * @param password 新密码
     */
    @Override
    public void updatePasswordById(Long id, String password) {
        log.debug("开始处理【修改管理员密码】的业务，id={}，password={}", id, password);
        // 不允许对id=1的管理员进行危险管理操作，返回NOT_FOUND错误，视为id=1的管理员不存在
        if (id == 1) {
            String message = "修改管理员密码失败！尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if (queryResult == null) {
            String message = "修改管理员密码失败！尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        Admin admin = new Admin();
        admin.setId(id);
        String encodedPassword = passwordEncoder.encode(password);
        admin.setPassword(encodedPassword);
        int rows = adminMapper.update(admin);
        if (rows != 1) {
            String message = "修改管理员密码失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }

    /**
     * 修改管理员基本信息
     * @param id                 管理员id
     * @param adminUpdateInfoDTO 封装了新基本资料的对象
     */
    @Override
    public void updateInfoById(Long id, AdminUpdateInfoDTO adminUpdateInfoDTO) {
        log.debug("开始处理【修改管理员基本资料】的业务，id={}，新基本资料={}", adminUpdateInfoDTO);
        // 不允许对id=1的管理员进行危险管理操作，返回NOT_FOUND错误，视为id=1的管理员不存在
        if (id == 1) {
            String message = "修改管理员基本资料失败！尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if (queryResult == null) {
            String message = "修改管理员基本资料失败！尝试访问的数据不存在！";
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        Admin admin = new Admin();
        BeanUtils.copyProperties(adminUpdateInfoDTO, admin);
        admin.setId(id);
        int rows = adminMapper.update(admin);
        if (rows != 1) {
            String message = "修改管理员基本资料失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }

    /**
     * 启用管理员
     * @param id 管理员id
     */
    @Override
    public void setEnable(Long id) {
        log.debug("开始处理【启用管理员账号】的业务：id={}", id);
        // 不允许对id=1的管理员进行危险管理操作，返回NOT_FOUND错误，视为id=1的管理员不存在
        if (id == 1) {
            String message = "启用管理员账号失败！尝试访问的数据不存在！";
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        AdminStandardVO adminStandardVO = adminMapper.getStandardById(id);
        if (adminStandardVO==null){
            String message = "启用失败，该用户不存在！";
            throw new ServiceException(ServiceCode.ERR_CONFLICT,message);
        }
        if (adminStandardVO.getEnable()==1){
            String message = "启用管理员账号失败！当前账号已经启用！";
            throw new ServiceException(ServiceCode.ERR_CONFLICT,message);
        }
        Admin admin = new Admin();
        admin.setId(id);
        admin.setEnable(1);
        int row = adminMapper.update(admin);
        if (row!=1){
            String message = "启用管理员失败,服务器忙,请稍后再试!";
            throw new ServiceException(ServiceCode.ERR_UPDATE,message);
        }
    }

    /**
     * 禁用管理员
     * @param id 管理员id
     */
    @Override
    public void setDisable(Long id) {
        log.debug("开始处理【禁用管理员账号】的业务：id={}", id);
        // 不允许对id=1的管理员进行危险管理操作，返回NOT_FOUND错误，视为id=1的管理员不存在
        if (id == 1) {
            String message = "禁用管理员账号失败！尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if (queryResult == null) {
            String message = "禁用管理员账号失败！尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        if (queryResult.getEnable() == 0) {
            String message = "禁用管理员账号失败！当前账号已经禁用！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        Admin admin = new Admin();
        admin.setId(id);
        admin.setEnable(0);
        int rows = adminMapper.update(admin);
        if (rows != 1) {
            String message = "禁用管理员账号失败！服务器忙，请稍后再次尝试！";
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }

    /**
     * 查询管理员列表
     * @return
     */
    @Override
    public List<AdminListItemVO> list() {
        log.debug("开始处理【查询管理员列表】的业务……");
        List<AdminListItemVO> list = adminMapper.list();
        Iterator<AdminListItemVO> iterator = list.iterator();
        while (iterator.hasNext()){
            AdminListItemVO admin = iterator.next();
            if (admin.getId()==1){
                iterator.remove();
                break;
            }
        }
        return list;
    }






}
